package ro.flashbite.sound
{	
	import flash.display.MovieClip;
	
	import ro.flashbite.interfaces.IDestroyable;
	import ro.flashbite.loggers.ILogger;
	import ro.flashbite.loggers.LoggerFactory;
	
	public final class SoundEnqueuer implements IDestroyable
	{	
		private var _list			:	Vector.<Sound2>;
		
		private var _loops			:	int;
		
		//reset value = -1; start value : 0; end value : _list.length - 1;
		private var _listIndex		:	int;
		//reset value = -1; start value: 0; end value : _loops - 1;
		private var _loopIndex		:	int;
		
		private var _speechManager	:	SpeechManager;
		
		private var _logger			:	ILogger;
		
		private var _currentSnd		:	Sound2;
		
		private var _internalCall	:	Function;
		private var _externalCall	:	Function;
		
		private var _type			:	String;
		
		// ================================================================================================================================
		// PUBLIC
		// ================================================================================================================================
		
		public function SoundEnqueuer(loggerID:String)
		{
			_constructor(loggerID);
		}
		private function _constructor(loggerID:String):void
		{
			_logger = LoggerFactory.getLogger("SoundEnqueuer - " + loggerID);
			
			_speechManager = new SpeechManager();
			
			reset();
		}
		
		// ================================================================================================================================
		// PUBLIC
		// ================================================================================================================================
		
		public function play(soundList:Vector.<Sound2>, mcMouth:MovieClip, mouthID:String, loops:uint, internalCall:Function, externalCall:Function = null):Boolean
		{
			_logger.debug("Play sounds..." + soundList);
			
			stop();
			reset();
			
			_list = soundList;
			//if (mcMouth && mouthID) {
				//_speechManager.setMouth(mcMouth, mouthID);
				setSpeechManagerNewMouth(mcMouth, mouthID);
			//}
			
			//if (mouthID) 	
				
			_loops = loops;
			_internalCall = internalCall;
			_externalCall = externalCall;
			
			//start
			return goPlayNextSound();
		}
		
		public function setSpeechManagerNewMouth(mcMouth:MovieClip, mouthID:String):void
		{
			if (_speechManager)
				_speechManager.setMouth(mcMouth, mouthID);
		}
		
		public function reset():void
		{
			//_logger.debug("reset()");
			
			_listIndex = 0;
			_loopIndex = 0;
			_list = null;
			_internalCall = null;
		}
		
		public function stop():void
		{
			//_logger.debug("stop()");
			
			if (_currentSnd) {
				_currentSnd.removeEventListener(Sound2Event.COMPLETE, onSoundComplete);
				_currentSnd.stop();
				_logger.debug("Stopping...." + _currentSnd.getId());
			} else {
				//_logger.debug("No sound to stop...");
			}
			
			//stop sync if mouth defined
			if (_speechManager && _speechManager.mouthID) {
				_speechManager.stopSync();
			}
		}
		
		public function isPlayingSound(sound:Sound2):Boolean
		{
			if (_list && _list.indexOf(sound) > -1) return true;
				
			return false;
		}

		// ================================================================================================================================
		// PRIVATE
		// ================================================================================================================================
		
		private function onSoundComplete(e:Sound2Event):void
		{
			//_logger.debug("onSoundComplete() soundID = " + (_currentSnd ? _currentSnd.getId() : " null"));
			
			if (_currentSnd) {
				_currentSnd.removeEventListener(Sound2Event.COMPLETE, onSoundComplete);
			}
			//check end of list
			if (++_listIndex < _list.length) {
				goPlayNextSound();
			} else {
				//reached end of list... check if loops are ending
				if (++_loopIndex < _loops) {
					//reset to first location in array
					_listIndex = 0;
					//play next sound
					goPlayNextSound();
				} else {
					//end -> call complete
					if (_internalCall != null) {
						//stop this
						stop();
						//call for cleanup in soundManager
						_internalCall(this);
						if (_externalCall != null) {
							//call for user endFunction call
							_externalCall();
						}
					}// else _logger.error("End of queue reached, But no callback defined");
				}
			}
		}
		
		private function goPlayNextSound():Boolean
		{
			//_logger.debug("goPlayNextSound() _listIndex : " + _listIndex + ", _loopIndex : " + _loopIndex);
			//stop sync on real speech objects
			if (_speechManager.mouthID)
				_speechManager.stopSync();
			//play next sound
			_currentSnd = _list[_listIndex];
			_currentSnd.addEventListener(Sound2Event.COMPLETE, onSoundComplete, false, 0, true);
			
			var isRealPlaying:Boolean = _currentSnd.play();
			_logger.debug("Playing sound id " + _currentSnd.getId() + ", with enqueuer: " + _logger.name);
			
			//sync....
			if (_speechManager.mouthID) {
				_speechManager.startSync(_currentSnd);
			}
			
			//return the status os sound
			return isRealPlaying;	
		}
		
		// ================================================================================================================================
		// DESTRUCTOR
		// ================================================================================================================================
		
		public function destroy():void
		{
			stop();
			reset();
			
			_list = null;
			if (_speechManager) {
				_speechManager.destroy();
				_speechManager = null;
			}
			
			_logger = null;
			
			_currentSnd = null;
			
			_internalCall = null;
			_externalCall = null;
			
			_type = null;
		}

		// ================================================================================================================================
		// GETTERS
		// ================================================================================================================================
		
		public function get list():Vector.<Sound2> { return _list; }
		
		public function get queueIsPlaying():Boolean 
		{ 
			if (_list) {
				return ( (_list.length != _listIndex) && (_loops != _loopIndex) );
			}
			
			return false; 
		}
		
		public function get speechManagerMouthID():String
		{
			if (_speechManager) return _speechManager.mouthID;
			else return null;
		}
		
		public function get queueIsComplete():Boolean 
		{ 
			if (_list) {
				return ( (_list.length == _listIndex) && (_loops == _loopIndex) );
			}
			
			return true; 
		}
		
		public function get isAvailable():Boolean
		{
			var isReseted:Boolean = (_listIndex == -1 && _loopIndex == 0 && _loops == 0);
			
			return isReseted || queueIsComplete;
		}

		public function get TYPE()			: String {	return _type; 	}
		public function set TYPE(v:String)	: void 	 { _type = v; 		}

	}
}